﻿namespace FitnessTracker.Packet
{
    using System;
    using FitnessTracker.Entities;

    public static class HxMPacketValueRangeValidator
    {
        private static readonly FitnessTrackerEntities FitnessTrackerEntities = new FitnessTrackerEntities();

        public static bool AreDataPointValuesInRange(byte[] buffer)
        {
            return IsBatteryValueInRange(buffer) &&
                   IsHeartRateValueInRange(buffer) &&
                   IsHeartBeatNumberInRange(buffer) &&
                   IsDistanceValueInRange(buffer) &&
                   IsInstanteniousSpeedValueInRange(buffer) &&
                   IsStridesValueInRange(buffer);
        }

        private static bool IsBatteryValueInRange(byte[] buffer)
        {
            if (buffer[HxMPacketStructure.BatteryChargeIndicatorOffset] > 100)
            {
                LogFaultyPacket(
                        buffer, 
                        string.Format(
                        "Battery Charge Reading our of range. Expected value was less than 100. Actuall was {0}",
                        buffer[HxMPacketStructure.BatteryChargeIndicatorOffset]));
                return false;
            }

            return true;
        }

        private static bool IsDistanceValueInRange(byte[] buffer)
        {
            const ushort Maximum = 4095; 
            var distanceBytes = new byte[2];
                distanceBytes[0] = buffer[HxMPacketStructure.DistanceOffset];
                distanceBytes[1] = buffer[HxMPacketStructure.DistanceOffset + 1];
                int distanceIn16ThOfMeter = BitConverter.ToUInt16(distanceBytes, 0);

            if (distanceIn16ThOfMeter > Maximum)
            {
                LogFaultyPacket(
                    buffer,
                    string.Format(
                    "Distance is out of range. Expected value was less than 4095. Actuall was {0}",
                    distanceIn16ThOfMeter));
                return false;
            }

            return true;
        }

        private static bool IsHeartBeatNumberInRange(byte[] buffer)
        {
            const byte Maximum = 255; 
            if (buffer[HxMPacketStructure.HeartBeatNumberOffset] > Maximum)
            {
                LogFaultyPacket(
                    buffer,
                    string.Format(
                    "Heart Beat Number is out of range. Expected value as less then 266. Actuall was {0}",
                    buffer[HxMPacketStructure.HeartRateOffset]));
                return false;
            }

            return true;
        }

        private static bool IsHeartRateValueInRange(byte[] buffer)
        {
            const byte Minimum = 30;
            const byte Maximum = 240; 
       
            if (buffer[HxMPacketStructure.HeartRateOffset] < Minimum ||
                buffer[HxMPacketStructure.HeartRateOffset] > Maximum)
            {
                LogFaultyPacket(
                    buffer,
                    string.Format(
                    "Heart Rate Reading is out of range. Expected value was between 30 and 240. Actuall was {0}",
                    buffer[HxMPacketStructure.HeartRateOffset]));
                return false;
            }

            return true;
        }

        private static bool IsInstanteniousSpeedValueInRange(byte[] buffer)
        {
            const ushort Maximum = 4095; 
            var instantaneousSpeedBytes = new byte[2];
                instantaneousSpeedBytes[0] = buffer[HxMPacketStructure.InstantaneousSpeedOffset];
                instantaneousSpeedBytes[1] = buffer[HxMPacketStructure.InstantaneousSpeedOffset + 1];
                var instantaneousSpeedInStepsOf1By256MetersPerSecond = BitConverter.ToUInt16(instantaneousSpeedBytes, 0);

            if (instantaneousSpeedInStepsOf1By256MetersPerSecond > Maximum)
            {
                LogFaultyPacket(
                    buffer,
                    string.Format(
                    "Speed reading is out of range. Expected value was less than 4095. Actuall was {0}",
                    instantaneousSpeedInStepsOf1By256MetersPerSecond));
                return false;
            }


            return true;
        }

        private static bool IsStridesValueInRange(byte[] buffer)
        {
             const ushort Maximum = 128; 
             
            if (buffer[HxMPacketStructure.StridesOffset] > Maximum)
            {
                LogFaultyPacket(
                    buffer,
                    string.Format(
                    "Strides Reading is out of range. Expected value was less than 255. Actuall was {0}",
                    buffer[HxMPacketStructure.StridesOffset]));
                return false;
            }

            return true;
        }

        private static void LogFaultyPacket(byte[] bufferData, string faultDescription)
        {
            var packetFaultsLog = new PacketFaultsLog
            {
                timeStamp = DateTime.Now,
                description = faultDescription,
                packet = bufferData
            };
            FitnessTrackerEntities.PacketFaultsLogs.Add(packetFaultsLog);
            FitnessTrackerEntities.SaveChanges();
        }
    }
}
